package cate.game.pvp.pointrace.simulator;

import cate.game.framework.advanced.AdvancedLongAttributes;
import cate.game.pvp.pointrace.data.PointRaceKV;
import cate.game.pvp.pointrace.data.PointRaceRank;
import cate.game.pvp.pointrace.data.PointRaceRankRwd;
import cate.game.pvp.pointrace.handler.PointRaceExcelQueryOperation;
import cate.game.pvp.pointrace.handler.PointRaceRankHandler;
import cate.game.pvp.pointrace.handler.PointRaceRankRwdOperation;
import cate.game.pvp.pointrace.timer.PointRaceTimerTask.Settings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;

import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

import static cate.game.event.pointrace.PointRaceTimerEvent.EventType.RANK_DAY_RWD;
import static cate.game.event.pointrace.PointRaceTimerEvent.EventType.RANK_SEASON_RWD;

@Slf4j
public class BothPointRaceRwdSimulator extends PointRaceSimulator {

    private final Supplier<PointRaceRankRwdOperation> rankRwdOperationSupplier;
    private final Supplier<PointRaceRankHandler> rankHandlerSupplier;
    private final Supplier<PointRaceExcelQueryOperation> excelQueryOperationSupplier;

    public BothPointRaceRwdSimulator(
            Supplier<PointRaceKV> kvSupplier,
            Supplier<PointRaceRankRwdOperation> rankRwdOperationSupplier,
            Supplier<PointRaceRankHandler> rankHandlerSupplier,
            Supplier<PointRaceExcelQueryOperation> excelQueryOperationSupplier) {
        super(kvSupplier);
        this.rankRwdOperationSupplier = Objects.requireNonNull(rankRwdOperationSupplier);
        this.rankHandlerSupplier = Objects.requireNonNull(rankHandlerSupplier);
        this.excelQueryOperationSupplier = Objects.requireNonNull(excelQueryOperationSupplier);
    }

    @Override
    public boolean isMatch(Settings settings) {
        return settings.getEventType() == RANK_DAY_RWD
                || settings.getEventType() == RANK_SEASON_RWD;
    }

    @Override
    public void runWith(Settings settings) {
        switch (settings.getEventType()) {
            case RANK_DAY_RWD:
                runRankDayRwdWith(settings);
                break;
            case RANK_SEASON_RWD:
                runRankSeasonRwdWith(settings);
                break;
        }
    }

    private void runRankDayRwdWith(Settings settings) {
        AdvancedLongAttributes attributes = getAttributes();
        PointRaceKV kv = getKV();

        if (attributes.hasAttribute(RANK_DAY_RWD.getFlag() + settings.getDay())) {
            return;
        }

        log.info("发送每日排行榜奖励, 第 {} 天", settings.getDay());

        PointRaceRankHandler rankHandler = getRankHandler();
        List<PointRaceRank> rankList = rankHandler.getRankFlow()
                .collectList()
                .blockOptional()
                .orElse(null);

        if (Objects.isNull(rankList) || rankList.isEmpty()) {
            log.error("积分赛排行榜为空! 第 {} 天", settings.getDay());
            attributes.setAttribute(RANK_DAY_RWD.getFlag() + settings.getDay());
            return;
        }

        List<PointRaceRankRwd> rankRwdList = Lists.newArrayList();
        PointRaceExcelQueryOperation excelQueryOperation = getExcelQueryOperation();

        for (int i = 0; i < rankList.size(); i++) {
            PointRaceRank rank = rankList.get(i);
            PointRaceRankRwd rwd = PointRaceRankRwd.ofDay(
                    rank.owner.uid,
                    kv.getSeason(),
                    rank.owner.base.srvId,
                    i + 1,
                    excelQueryOperation.getRankDayRwd(i + 1),
                    settings.getDay()
            );
            rankRwdList.add(rwd);
        }

        PointRaceRankRwdOperation rankRwdOperation = getRankRwdOperation();
        rankRwdOperation.upsert(rankRwdList);

        attributes.setAttribute(RANK_DAY_RWD.getFlag() + settings.getDay());
    }

    private void runRankSeasonRwdWith(Settings settings) {
        AdvancedLongAttributes attributes = getAttributes();
        if (attributes.hasAttribute(RANK_SEASON_RWD.getFlag())) {
            return;
        }

        PointRaceKV kv = getKV();

        log.info("发送赛季排行榜奖励");

        PointRaceRankHandler rankHandler = getRankHandler();
        List<PointRaceRank> rankList = rankHandler.getRankFlow()
                .collectList()
                .blockOptional()
                .orElse(null);

        if (Objects.isNull(rankList) || rankList.isEmpty()) {
            log.error("积分赛赛季 {} 排行榜为空!", kv.getSeason());
            attributes.setAttribute(RANK_SEASON_RWD.getFlag());
            return;
        }

        List<PointRaceRankRwd> rankRwdList = Lists.newArrayList();
        PointRaceExcelQueryOperation excelQueryOperation = getExcelQueryOperation();

        for (int i = 0; i < rankList.size(); i++) {
            PointRaceRank rank = rankList.get(i);
            PointRaceRankRwd rwd = PointRaceRankRwd.ofSeason(
                    rank.owner.uid,
                    kv.getSeason(),
                    rank.owner.base.srvId,
                    i + 1,
                    excelQueryOperation.getRankSeasonRwd(i + 1),
                    settings.getDay()
            );
            rankRwdList.add(rwd);
        }

        PointRaceRankRwdOperation rankRwdOperation = getRankRwdOperation();
        rankRwdOperation.upsert(rankRwdList);

        attributes.setAttribute(RANK_SEASON_RWD.getFlag());
    }

    private PointRaceRankRwdOperation getRankRwdOperation() {
        return Objects.requireNonNull(rankRwdOperationSupplier.get());
    }

    private PointRaceRankHandler getRankHandler() {
        return Objects.requireNonNull(rankHandlerSupplier.get());
    }

    private PointRaceExcelQueryOperation getExcelQueryOperation() {
        return Objects.requireNonNull(excelQueryOperationSupplier.get());
    }
}
